package org.example.learn.asm;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestAsm  extends ClassLoader{

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 二进制字节码
        byte[] bytes = generate();

        outputClazz(bytes);

        Class<?> clazz = new TestAsm().defineClass("org.example.learn.asm.TestA",bytes,0,bytes.length);

        Method main = clazz.getMethod("main",String[].class);

        main.invoke(null,new Object[]{new String[]{}});
    }

    public static byte[] generate(){
        // 创建 ClassWriter
        ClassWriter classWriter = new ClassWriter(0);

//        // init 方法
//        {
//            MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC,"<init>","()V",null,null);
//            mv.visitCode();
//            mv.visitVarInsn(Opcodes.ALOAD,0);
//            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Object","<init>","()V",false);
//            mv.visitInsn(Opcodes.RETURN);
//            mv.visitMaxs(1,1);
//            mv.visitEnd();
//        }

        // 定义对象头、版本号、修饰符、全类名、签名、父类、实现的接口
        classWriter.visit(Opcodes.V1_8,Opcodes.ACC_PUBLIC,"org/example/learn/asm/TestA",null,"java/lang/Object",null);

        // 添加方法：修饰符、方法名、描述符、签名、异常
        MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC,"main","([Ljava/lang/String;)V",null,null);

        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream;");

        // 加载指令：获取静态属性
        methodVisitor.visitLdcInsn("Hello ASM World!");

//        methodVisitor.visitLdcInsn("123");

        //调用
        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/String;)V",false);

        //返回值
        methodVisitor.visitInsn(Opcodes.RETURN);

        //设置操作数栈的深度和局部变量的大小
        methodVisitor.visitMaxs(2,1);
        //方法结束
        methodVisitor.visitEnd();

        // 类结束
        classWriter.visitEnd();

        return classWriter.toByteArray(); // 生成字节数组
    }

    private static void outputClazz(byte[] bytes){
        FileOutputStream out = null;

        try {
            String path = TestAsm.class.getResource("/").getPath() + "TestA.class";
            out = new FileOutputStream(path);
            System.out.println("TestA类输出路径：" + path);
            out.write(bytes);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
